package core.helpers;

import org.testng.Assert;
import org.testng.TestNGException;

import core.ApplicationManager;

/**
 * Class provides functions for values testing
 */
public class TestHelper
{
	protected static ApplicationManager manager;

	/**
	 * Initializes TestHelper
	 * @param p_manager ApplicationManager instance
	 */
	public TestHelper(ApplicationManager p_manager)
	{
		manager = p_manager;
	}

	/**
	 * Tests for equivalence
	 * @param p_actual Actual value
	 * @param p_expected Expected value
	 */
	public void forEquivalence(boolean p_actual, boolean p_expected)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
			manager.testModel().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError();
		}
	}

	/**
	 * Tests for equivalence
	 * @param p_actual Actual value
	 * @param p_expected Expected value
	 * @param p_errorMessage Error message
	 */
	public void forEquivalence(boolean p_actual, boolean p_expected, String p_errorMessage)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
			manager.testModel().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError(p_errorMessage);
		}
	}

	/**
	 * Tests for true
	 * @param p_actual Actual value
	 */
	public void forTrue(boolean p_actual)
	{
		try
		{
			Assert.assertTrue(p_actual);
			manager.testModel().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError();
		}
	}

	/**
	 * Tests for true
	 * @param p_actual Actual value
	 * @param p_errorMessage Error message
	 */
	public void forTrue(boolean p_actual, String p_errorMessage)
	{
		try
		{
			Assert.assertTrue(p_actual);
			manager.testModel().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError(p_errorMessage);
		}
	}

	/**
	 * Tests for false
	 * @param p_actual Actual value
	 * @param p_errorMessage Error message
	 */
	public void forFalse(boolean p_actual, String p_errorMessage)
	{
		try
		{
			Assert.assertFalse(p_actual);
		}
		catch (AssertionError p_ex)
		{
			throwError(p_errorMessage);
		}
	}

	/**
	 * Tests for false
	 * @param p_actual Actual value
	 */
	public void forFalse(boolean p_actual)
	{
		try
		{
			Assert.assertFalse(p_actual);
			manager.testModel().setStatus(1);
		}
		catch (AssertionError p_ex)
		{
			throwError();
		}
	}

	/**
	 * Tests for false
	 */
	public void forErrors()
	{
		if (!manager.log().isErrors())
		{
			manager.testModel().setStatus(1);
		}
		else
		{
			manager.testModel().setStatus(0);
			throwError();
		}
	}

	/**
	 * Throws assertion error
	 * @param p_errors Error messages list
	 * @throws AssertionError
	 */
	protected void throwError(String... p_errors) throws AssertionError
	{
		if (p_errors.length > 0)
		{
			for (int i = 0; i < p_errors.length; i++)
			{
				manager.log().writeError(p_errors[i]);
			}
		}

		if (manager.testModel().getStatus() != 0)
		{
			manager.testModel().setStatus(0);
		}
		throw new AssertionError(manager.log().getErrorsAndWarnings());
	}

	/**
	 * Compares numbers to verify that actual value greater than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forGreaterOrEqual(String p_actual, String p_expected, String p_message)
	{
		try
		{
			Integer actual = Integer.valueOf(p_actual);
			Integer expected = Integer.valueOf(p_expected);
			Assert.assertTrue(actual >= expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is lower than expected [" + p_expected + "] ");
		}
	}

	/**
	 * Compares numbers to verify that actual value greater than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forGreaterOrEqual(Integer p_actual, Integer p_expected, String p_message)
	{
		try
		{
			Assert.assertTrue(p_actual >= p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is lower than expected [" + p_expected + "] ");
		}
	}

	/**
	 * Compares numbers to verify that actual value lover than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forLowerOrEqual(String p_actual, String p_expected, String p_message)
	{
		try
		{
			Integer actual = Integer.valueOf(p_actual);
			Integer expected = Integer.valueOf(p_expected);
			Assert.assertTrue(actual <= expected);
		}
		catch (AssertionError E)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is greater than expected [" + p_expected + "]");
		}
	}

	/**
	 * Compares numbers to verify that actual value lover than expected
	 * @param p_actual
	 * @param p_expected
	 * @param p_message
	 */
	public void forLoverOrEqual(Integer p_actual, Integer p_expected, String p_message)
	{
		try
		{
			Assert.assertTrue(p_actual <= p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual [" + p_actual + "] is greater than expected [" + p_expected + "] ");
		}
	}

	/**
	 * Gets current method name
	 * @return Method name
	 */
	private String getMethodName()
	{
		StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
		StackTraceElement stackTraceElement = stacktrace[4];
		String methodName = stackTraceElement.getMethodName();
		return methodName;
	}

	public void assertEquals(String p_actual, String p_expected, String p_message)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual: [" + p_actual + "] is NOT equal Expected: [" + p_expected + "] ");
		}
	}

	public void assertGreater(Integer p_expected, Integer p_actual, String p_message, Boolean isThrowable)
	{
		try
		{
			Assert.assertTrue(p_actual > p_expected);

		}
		catch (AssertionError p_ex)
		{
			if (isThrowable)
			{
				throw new TestNGException(p_message + " Actual [" + p_actual + "] is NOT greater than [" + p_expected + "] ");
			}
			manager.log().error(p_message + " : Actual [" + p_actual + "] is NOT greater than [" + p_expected + "] ");
		}
	}

	public void assertLower(Integer p_expected, Integer p_actual, String p_message, Boolean isThrowable)
	{
		try
		{
			Assert.assertTrue(p_actual < p_expected);

		}
		catch (AssertionError p_ex)
		{
			if (isThrowable)
			{
				throw new TestNGException(p_message + " : Actual [" + p_actual + "] is NOT lower than [" + p_expected + "] ");
			}
			else
			{
				manager.log().error(p_message + " : Actual [" + p_actual + "] is NOT lower than [" + p_expected + "] ");
			}
		}
	}

	public void assertEquals(boolean p_actual, boolean p_expected, String p_message)
	{
		try
		{
			Assert.assertEquals(p_actual, p_expected);
		}
		catch (AssertionError p_ex)
		{
			manager.log().error(p_message + " : Actual: [" + p_actual + "] is not equal Expected: [" + p_expected + "] ");
		}
	}
}
